package com.inspectortime.calendar;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import com.inspectortime.domain.ScheduleRule;
import com.inspectortime.domain.type.FrequencyType;
import com.inspectortime.util.CalendarUtil;


/**
 * @author Owner
 * @version 1.0
 * @created 27-Nov-2007 7:41:10 AM
 */
public class Day {
	
	private List<Timeslot> timeslots = new ArrayList<Timeslot>();
	private Calendar calendar ;

	public Day(int month, int day, int year, int dayOfWeek){
		this.calendar = CalendarUtil.createDayCalendar(year, month, day);
	}
	

	public void addTimeslot(Timeslot newTimeslot) {
		//loop thru and compare timeSlots
		Timeslot toRemove = null;
		for (Timeslot timeslot : timeslots) {
				
			if (timeslot.overlapsWith(newTimeslot)) {
			
				//the new slot overlaps with the original slot in this place,
				//so we'll override it with the new one
				//timeslots.remove(timeslot);
				toRemove = timeslot;
			}
		} //for
		
		if (toRemove != null) {
			timeslots.remove(toRemove);
		}
		timeslots.add(newTimeslot);
	}
	
	
	public void addTimeslots(List<Timeslot> newTimeslots) {
		for (Timeslot newTimeslot: newTimeslots) {
			addTimeslot(newTimeslot);
		}
	}
	
	/**
	 * Return true if this scheduleRule applies to the passed in day 
	 * (ie the rule's frequency matches the day of week, etc)
	 * 
	 * @param day
	 * @return true if this rule can apply to the passed in day
	 */
	public boolean canPopulateFrom(ScheduleRule rule) {
		Calendar dayCal = null;
		
		//If a startdate and/or enddate have been defined,
		//make sure the day falls within them
		if (rule.getStartDate() != null || rule.getEndDate() != null) {
			dayCal = CalendarUtil.createDayCalendar(this.getYear(), this.getMonth(), this.getDay());
			
			if ((rule.getStartDate() != null && dayCal.before(rule.getStartDate())) ||
					(rule.getEndDate() != null && dayCal.after(rule.getEndDate()))) {
				return false;
			}
		}
		
		//Now do the frequency logic
		if (rule.getFrequencyType() == FrequencyType.DAY_OF_WEEK) {
			//For this frequencyType, refer to the Schedule's ruleUnits,
			//which will represent days of week
			for (int i = 0; i < rule.getUnits().length; i++) {
				if (rule.getUnits()[i] == this.getDayOfWeek()) {
					return true;
				}
			}
		} else if (rule.getFrequencyType() == FrequencyType.SINGLE_DAY) {
			
			if (CalendarUtil.isOverlapping(rule.getStartDate(), rule.getEndDate(), dayCal, null)) {
				return true;
			}
		}
		
		return false;
	}
	
	/**
	 * If the day passed in contains appropriate values for this ScheduleRule 
	 * (matching date, day of week, etc), then populate the day with a timeslot
	 * defined by this rule's properties (startHour, startMinute, endHour, endMinute, isAvailable)
	 * 
	 * @param day
	 */
	public void populateFrom(ScheduleRule rule) {
		this.addTimeslot(new Timeslot(rule));
	}
	
	public List<Timeslot> getTimeslots() {
		return timeslots;
	}
	
	/**
	 * @return true if this day contains one or more timeslots
	 */
	public boolean hasTimeslot() {
		return !timeslots.isEmpty();
	}
	
	/**
	 * @return true if this day contains one or more "open" timeslots
	 * (available for scheduling)
	 */
	public boolean hasAvailableTimeslot() {
		if (hasTimeslot()) {
			for (Timeslot slot : timeslots) {
				if (slot.isAvailable()) {
					return true;
				}
			}
		}
		return false;
	}
	
	public int getDay() {
		return calendar.get(Calendar.DAY_OF_MONTH);
	}

	public int getMonth() {
		return calendar.get(Calendar.MONTH);
	}

	public int getYear() {
		return calendar.get(Calendar.YEAR);
	}

	public int getDayOfWeek() {
		return calendar.get(Calendar.DAY_OF_WEEK);
	}
	
	public void disableAllTimeslots() {
		if (this.hasTimeslot()) {

			for (Timeslot timeslot : this.getTimeslots()) {
				timeslot.setAvailable(false);
			}
		}
	}
	
	public boolean equalsDate(Date time) {
		Calendar cal = Calendar.getInstance();
		cal.setTime(time);
		
		if (this.getDay() == cal.get(Calendar.DAY_OF_MONTH) &&
			this.getMonth() == cal.get(Calendar.MONTH) &&
			this.getYear() == cal.get(Calendar.YEAR)) {
			return true;
		}
		return false;
	}

	public void finalize() throws Throwable {

	}
	
	public String toString() {
		SimpleDateFormat dateFormat = new SimpleDateFormat("EEE, MMM dd, yyyy");
		return dateFormat.format(calendar.getTime());
		
	}
	
	/**
	 * @return this day as a Date object to take advantage of Freemarker's Date format features
	 */
	public Date toDate() {
		return calendar.getTime();
	}
	
	/**
	 * @param dateToCheck
	 * @return true if the date represented by this Day object is the same as dateToCheck
	 */
	public boolean isSameDate(Calendar dateToCheck) {
		if (dateToCheck.get(Calendar.YEAR) == calendar.get(Calendar.YEAR) &&
				dateToCheck.get(Calendar.MONTH) == calendar.get(Calendar.MONTH) &&
				dateToCheck.get(Calendar.DATE) == calendar.get(Calendar.DATE)) {
			return true;
		}
			
		return false;
	}
	
	/**
	 * 
	 * @param month
	 * @param day
	 * @param year
	 * @return true if the date represented by this Day object is the same as the passed in month, day, year
	 */
	public boolean isSameDate(int month, int day, int year) {
		if (month == calendar.get(Calendar.MONTH) &&
			day == calendar.get(Calendar.DAY_OF_MONTH) &&
			year == calendar.get(Calendar.YEAR)) {
			return true;
		}
			
		return false;
	}
	
	
	/**
	 * 
	 * @param dateToCheck
	 * @return true if the date represented by this Day object is before the one passed in
	 */
	public boolean isBefore(Calendar dateToCheck) {
		if (calendar.before(dateToCheck)) {
			return true;
		}
		return false;
	}
	
	
	/**
	 * 
	 * @param dateToCheck
	 * @return true if the date represented by this Day object is after the one passed in
	 */
	public boolean isAfter(Calendar dateToCheck) {
		if (calendar.after(dateToCheck)) {
			return true;
		}
		return false;
	}

}